#pragma once

#include "Widget.hpp"




namespace Engine
{
	namespace Ui
	{
		/**
		 * A frame represents a widget, that has some kind of border drawn around the actual
		 * widget. Technically, however, the border is drawn outside the widget,thus some adjustements
		 * to the size must be made.
		 * A border may have a simple shape (hard edged, several pixels in width) or a more complex
		 * one, like a rounded border.
		 */
		class ENGINE_UI_API Frame : public Widget
		{
		public:

			SHARED(Frame);

			typedef std::map<Border::Type, Glyph>    GlyphMap;
			typedef std::pair<Border::Type, Glyph>   GlyphPair;

		protected:

			/**
			 * Create a Frame Widget.
			 */
			Frame(Widget::weak_ptr parent);

		public:

			MAKE_SHARED1(Frame, Widget::weak_ptr);



			/**
			 * Get the extends of the nonclient area.
			 * The returned vector contains the following information: (left, top, right, bottom).
			 * This function is called alot and should not perform heavy computations.
			 */
			virtual int4 padding() const;



			/**
			 * Test if the frame (only the frame, not the client area)
			 * is being hovered by the mouse.
			 */
			Border::Type hoveredBorder() const;



			/**
			 * Returns the extends for the background part of the frame.
			 */
			int2 extends() const;



			/**
			 * Get the color of the border of this frame.
			 */
			math::color currentBorderColor() const;




			/**
			 * Calculates the extends for the given set of glyphs.
			 */
			static int4 calculateExtends(const GlyphMap& glyphs);

		protected:

			/**
			 * Get the type of this widget.
			 */
			virtual Widgets::Type type() const;

			/**
			 * This function is bound to the stateChanged() signal and requests the current glyphs
			 * that should be used to render this frame.
			 */
			void onStateChanged(Widget::weak_ptr that);

			/**
			 * Updates the widget, based on the current state.
			 * All widgets will be updated, no matter what their current state is.
			 */
			virtual void update(NestedState& state);

			/**
			 * Renders the frame around this widget.
			 */
			virtual void renderAdditional(Quads& quads, const NestedState& state);

			/**
			 * Calculate how many quads need to be rendered to visualize this frame.
			 *
			 * @return obviously the number of quads [0,8]
			 */
			virtual uint32 numAdditionalQuads() const;



			/**
			 * Do a hit test against all (available) glyphs of the frame.
			 */
			Border::Type hitTest(const GlyphMap& glyphs, const NestedState& state) const;

			/**
			 * Transform the given source rect into the coordinate system
			 * of this widget.
			 */
			math::rectangle<int> frameRect(Border::Type border, const intsize2& clientSize, const int4& extends) const;

			/**
			 * Get the offset of the frame's upper left edge to
			 * the upper left edge of the client area.
			 */
			int2 offset() const;

			/**
			 * Renders the frame with the giphen glyphs.
			 */
			void renderFrame(Quads& quads, const int2& screenPos, const intsize2& clientSize, const GlyphMap& glyphs, const int4& extends, const math::color& color) const;

		private:

			GlyphMap       m_backgroundGlyphs;

			int4           m_padding;
			int2           m_extends;

			Border::Type   m_hoveredBorder;
		};
		///////////////////////////////////////////////////////////////////////////////////////////
	}
	///////////////////////////////////////////////////////////////////////////////////////////////
}
///////////////////////////////////////////////////////////////////////////////////////////////////
